package com.alibaba.csp.sentinel.dashboard.rule.nacos;

/**
 * packageName com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosDynamicRulePublisher
 *
 * @author liudonghai
 * @version JDK 11
 * @date 2025/8/3
 * @description nacos规则发布
 */

import com.alibaba.csp.sentinel.dashboard.config.NacosRuleConstants;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.RuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * Nacos动态规则发布器抽象类
 * 提供通用的规则发布功能，减少重复代码
 */
public abstract class NacosDynamicRulePublisher<T extends RuleEntity> implements DynamicRulePublisher<List<T>> {

    private static final Logger logger = LoggerFactory.getLogger(NacosDynamicRulePublisher.class);

    private ConfigService configService;
    private Converter<List<T>, String> converter;

    public NacosDynamicRulePublisher(ConfigService configService, Converter<List<T>, String> converter) {
        this.configService = configService;
        this.converter = converter;
    }

    /**
     * 获取数据ID后缀
     * @return 数据ID后缀
     */
    protected abstract String getDataIdPostfix();

    /**
     * 生成完整数据ID
     * @param appName 应用名称
     * @return 完整数据ID
     */
    private String genDataId(String appName) {
        return appName + getDataIdPostfix();
    }

    @Override
    public void publish(String app, List<T> rules) throws Exception {
        // 验证应用名称不能为空
        AssertUtil.notEmpty(app, "app name cannot be empty");

        // 如果规则为空，直接返回
        if (rules == null) {
            return;
        }

        // 将规则列表转换为 JSON 字符串
        String ruleString = converter.convert(rules);
        String dataId = genDataId(app);

        logger.info("Publish rules to Nacos, dataId: {}, rules: {}", dataId, ruleString);

        // 发布配置到 Nacos
        boolean result = configService.publishConfig(
                dataId,                                    // dataId
                NacosRuleConstants.GROUP_ID,              // groupId: SENTINEL_GROUP
                ruleString,                               // 配置内容: JSON 格式的规则
                ConfigType.JSON.getType()                 // 配置类型: JSON
        );

        if (!result) {
            logger.error("Publish rules to Nacos failed, dataId: {}", dataId);
            throw new RuntimeException("Publish rules to Nacos failed, dataId: " + dataId);
        }

        logger.info("Publish rules to Nacos success, dataId: {}", dataId);
    }
}




